package com.zoe.onelink.logging.trace.feign;

import brave.Span;
import brave.Tracer;
import com.alibaba.fastjson.JSON;
import com.zoe.onelink.common.constant.TraceSpanConstant;
import com.zoe.onelink.logging.trace.property.TraceLogProperties;
import com.zoe.onelink.util.StrUtil;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.RequiredArgsConstructor;
import org.springframework.core.annotation.Order;

import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2022</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2022-05-07
 */
@RequiredArgsConstructor
@Order(3000)
public class FeignTraceLogInterceptor implements RequestInterceptor {

    private final Tracer tracer;
    private final TraceLogProperties.FeignLogProperties feignLogProperties;

    @Override
    public void apply(RequestTemplate requestTemplate) {
        Span span = this.tracer.nextSpan().kind(Span.Kind.CLIENT).start();
        String requestUri = StrUtil.subBefore(requestTemplate.url(), "?", false);
        span.name("[FEIGN] " + requestUri);
        span.tag(TraceSpanConstant.LOG_TYPE, TraceSpanConstant.LogType.FEIGN);
        span.tag(TraceSpanConstant.HTTP_URL, requestTemplate.feignTarget().url() + requestTemplate.url());
        span.tag(TraceSpanConstant.HTTP_METHOD, requestTemplate.method());
        this.traceHeader(span, requestTemplate);
        if (requestTemplate.body() == null) {
            span.tag(TraceSpanConstant.HTTP_PARAM, JSON.toJSONString(requestTemplate.queries()));
        } else {
            span.tag(TraceSpanConstant.HTTP_PARAM, new String(requestTemplate.body(), StandardCharsets.UTF_8));
        }
        span.finish();
    }

    private void traceHeader(Span span, RequestTemplate requestTemplate) {
        Map<String, Collection<String>> headerMap = requestTemplate.headers();
        List<String> includeHeaders = feignLogProperties.getIncludeHeaders();
        if (includeHeaders == null) {
            span.tag(TraceSpanConstant.HTTP_HEADER, JSON.toJSONString(headerMap));
            return;
        }
        Map<String, Collection<String>> logHeader = new HashMap<>(includeHeaders.size());
        includeHeaders.forEach(headerName -> logHeader.put(headerName, headerMap.get(headerName)));
        span.tag(TraceSpanConstant.HTTP_HEADER, JSON.toJSONString(logHeader));
    }

}
